﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.Util;
using System;
using System.Windows;

namespace PSE.Deployment.SetupBase.UI.CustomComponents
{
    public class TreeViewModel : INotifyPropertyChanged
    {
        private bool _isEnabled = true;
        private bool? _isChecked = false;
        private TreeViewModel _parent;

        public event PropertyChangedEventHandler PropertyChanged;
        public event CheckedChangingEventHandler CheckStateChanging;
        public delegate void CheckedChangingEventHandler(object sender, CheckedChangingEventArgs e);

        public event CheckedChangedEventHandler CheckStateChanged;
        public delegate void CheckedChangedEventHandler(object sender, CheckedChangedEventArgs e);

        public bool? IsChecked
        {
            get { return _isChecked; }
            set { SetIsChecked(value, true, true); }
        }

        /// <summary>
        /// Propriedade utilizada para controlar o estado do item da treeview
        /// </summary>
        public bool IsEnabled
        {
            get
            {
                return _isEnabled;
            }
            set
            {
                _isEnabled = value;
                this.OnPropertyChanged("IsEnabled");
            }
        }

        public string Id { get; set; }
        public string Name { get; set; }
        public List<TreeViewModel> Children { get; set; }
        public bool IsInitiallySelected { get; set; }

        public TreeViewModel(string id, string name)
        {
            this.Id = id;
            this.Name = name;
            this.Children = new List<TreeViewModel>();
        }

        public void Initialize()
        {
            foreach (TreeViewModel child in this.Children)
            {
                child._parent = this;
                child.Initialize();
            }
        }

        private void SetIsChecked(bool? value, bool updateChildren, bool updateParent)
        {
            if (_isChecked == value)
                return;

            CheckedChangingEventArgs e = new CheckedChangingEventArgs(value);
            if (CheckStateChanging != null)
                CheckStateChanging(this, e);

            if (!e.Cancel)
            {
                _isChecked = value;

                if (updateChildren && _isChecked.HasValue)
                    this.Children.ForEach(c => c.SetIsChecked(_isChecked, true, false));

                if (updateParent && _parent != null)
                    _parent.VerifyCheckState();

                if (CheckStateChanged != null)
                    CheckStateChanged(this, new CheckedChangedEventArgs(value));
            }

            this.OnPropertyChanged("IsChecked");
        }

        public void VerifyCheckState()
        {
            //se nao houver filhos, n alterar o status por se tratar de um no
            //se todos estao desmarcados, estado deve ser desmarcado
            //se houver ao menos um filho marcado , estado deve ser parcial
            //se todos os filhos estiverem marcados, estado deve ser marcado
            if (this.Children.Count == 0)
            {
                return;
            }
            else if (this.Children.Count(c => c.IsChecked == false) == this.Children.Count)
            {
                this.SetIsChecked(false, false, true);
            }
            else if (this.Children.Count(c => c.IsChecked == true) == this.Children.Count)
            {
                this.SetIsChecked(true, false, true);
            }
            else
            {
                this.SetIsChecked(null, false, true);
            }
        }

        private void OnPropertyChanged(string prop)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged.BeginInvoke(this, new PropertyChangedEventArgs(prop), null, null);
        }
    }

    public class CheckedChangingEventArgs : EventArgs
    {
        bool _cancel;
        bool? _isChecked;

        public bool Cancel
        {
            get { return _cancel; }
            set { _cancel = value; }
        }

        public bool? IsChecked
        {
            get { return _isChecked; }
            set { _isChecked = value; }
        }

        public CheckedChangingEventArgs(bool? isChecked)
        {
            this._isChecked = isChecked;
        }
    }

    public class CheckedChangedEventArgs : EventArgs
    {
        bool? _isChecked;

        public bool? IsChecked
        {
            get { return _isChecked; }
            set { _isChecked = value; }
        }

        public CheckedChangedEventArgs(bool? isChecked)
        {
            this._isChecked = isChecked;
        }
    }
}